package com.skyline.wo.controller;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.imagine.provider.fastdfs.FastDFSFileOperator;
import net.imagine.provider.skyline.ImageCropResult;
import net.imagine.provider.skyline.ImageCutter;
import net.imagine.provider.skyline.ImageResizeResult;
import net.imagine.provider.skyline.LocalImageResizeTask;
import net.imagine.provider.skyline.SkylineImageCropTask;
import net.imagine.provider.skyline.SkylineImagineUtils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

import com.skyline.base.controller.BaseController;
import com.skyline.base.exception.NoOperatePermissionException;
import com.skyline.base.exception.NoResourceException;
import com.skyline.base.exception.NoVisitPermissionException;
import com.skyline.base.exception.NotLoginException;
import com.skyline.base.exception.OperateFailedException;
import com.skyline.base.type.ResourceType;
import com.skyline.common.bean.Page;
import com.skyline.common.util.AuthorityUtil;
import com.skyline.common.util.CommonUtils;
import com.skyline.common.util.Constant;
import com.skyline.common.util.ViewPaths;
import com.skyline.common.util.WebHelper;
import com.skyline.common.validation.Errors;
import com.skyline.common.validation.ValidationUtils;
import com.skyline.user.model.User;
import com.skyline.user.service.PersonalInfoService;
import com.skyline.wo.model.Album;
import com.skyline.wo.model.Photo;

/**
 * 相册模块的Controller
 * 
 * @author wuqh
 * */
@Controller
@RequestMapping(value = "/album")
public class AlbumController extends BaseController {
	private static final Log LOGGER = LogFactory.getLog(AlbumController.class);
	private static final String URL_PREFIX = "/album";

	@Autowired
	private PersonalInfoService personalInfoService;

	private @Value("${album.cover.defaultCover}")
	String cover;
	private @Value("${album.cover.defaultExt}")
	String ext;
	@Autowired
	private ImageCutter crop;
	private @Value("${imagine.protraitSize}")
	int portraitSize;
	@Autowired(required = false)
	private FastDFSFileOperator fileOperator;

	private @Value("${album.listalbum.pagesize}")
	int listAlbumPageSize;
	private @Value("${album.listphoto.pagesize}")
	int listPhotoPageSize;

	/**
	 * 相册首页，显示ownerId指定用户的所有相册（包括头像相册）
	 * 
	 * 转到相册列表页面
	 * 
	 * @param ownerId
	 *            用户ID
	 * @param page
	 * */
	@RequestMapping(value = "/list/{ownerId}", method = RequestMethod.GET)
	public ModelAndView listAlbum(@PathVariable("ownerId") Long ownerId, Page page) {
		long viewerId = getViewerId();
		int authority = AuthorityUtil.getAuthority(null, ownerId);
		page.setSize(listAlbumPageSize);
		List<Album> albums = albumService.listAlbumsWithPortraitAlbum(ownerId, viewerId, authority, page);
		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_LISTALBUM);
		// 设置request
		view.addObject("page", page);
		view.addObject("albums", albums);
		if (!CollectionUtils.isEmpty(albums)) {
			view.addObject("ownerId", albums.get(0).getOwnerId());
			view.addObject("ownerName", albums.get(0).getOwnerNickname());
		} else {
			LOGGER.warn("数据异常，取到ID为:" + ownerId + "的相册列表为空，但是实际上至少会返回头像相册");
		}
		return view;
	}

	/**
	 * 照片列表页面，显示albumId指定相册
	 * 
	 * 转到相册列表页面
	 * 
	 * @param albumId
	 *            用户ID
	 * @param page
	 * */
	@RequestMapping(value = "/view/{albumId}", method = RequestMethod.GET)
	public ModelAndView viewAlbum(@PathVariable("albumId") Long albumId, Page page) {
		boolean addVisitCount = !checkVisitedAndLogFootprint(albumId, ResourceType.ALBUM);
		long viewerId = getViewerId();

		page.setSize(listPhotoPageSize);

		Album album = albumService.getAlbumById(albumId);
		// 判断权限
		int authority = checkAndReturnAuthority(album);

		List<Photo> photos = albumService.listPhotosOfAlbum(albumId, viewerId, authority, page, addVisitCount);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_VIEWALBUM);
		view.addObject("ownerId", album.getOwnerId());
		view.addObject("ownerName", album.getOwnerNickname());
		view.addObject("albumId", album.getId());
		view.addObject("page", page);
		view.addObject("photos", photos);
		view.addObject("album", album);

		return view;
	}

	/**
	 * 图片展示页面，显示photoId指定图片
	 * 
	 * 转到相册列表页面
	 * 
	 * @param albumId
	 *            用户ID
	 * */
	@RequestMapping(value = "/photo/{photoId}", method = RequestMethod.GET)
	public ModelAndView viewPhoto(@PathVariable("photoId") Long photoId) {
		long viewerId = getViewerId();
		// 此处不增加浏览数，统一在通过ajax方式获取图片信息是处理
		boolean addVisitCount = false;

		Photo photo = albumService.getPhotoDetailById(photoId, viewerId, addVisitCount);
		// 判断权限
		int authority = checkAndReturnAuthority(photo);

		List<Photo> photos = albumService.listPhotoFilesOfAlbum(photo.getAlbumId(), authority);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_VIEWPHOTO);
		view.addObject("photo", photo);
		view.addObject("photos", photos);

		return view;
	}

	/**
	 * 删除相册
	 * 
	 * @param albumId
	 *            相册Id
	 * @param page
	 * */
	@RequestMapping(value = "/delalbum/{albumId}", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView deleteAlbum(@PathVariable("albumId") long albumId, Page page) {
		long userId = getViewerId();
		albumService.deleteAlbum(albumId, userId);

		String url = buildRecirectPath(URL_PREFIX + "/list/" + userId);
		url = url + "?curpage=" + page.getCurpage();
		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	/**
	 * 打开修改相册页面
	 * 
	 * @param albumId
	 *            相册Id
	 * @param page
	 * */
	@RequestMapping(value = "/editalbum/{albumId}", method = RequestMethod.GET)
	public ModelAndView editAlbum(@PathVariable("albumId") Long albumId, Page page) {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();

		Album album = albumService.getAlbumForChange(albumId, userId);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_EDITALBUM);
		view.addObject("album", album);
		view.addObject("page", page);

		return view;
	}

	/**
	 * 修改相册信息
	 * 
	 * @param albumId
	 *            相册Id
	 * @param album
	 * @param page
	 * @param request
	 * */
	@RequestMapping(value = "/editalbum/{albumId}", method = RequestMethod.POST)
	public ModelAndView editAlbum(@PathVariable("albumId") Long albumId, Album album, Page page) {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();

		String errMsg = validateForm("editAlbumForm", album);
		if (errMsg != null) {
			ModelAndView returnMav = editAlbum(albumId, page);
			return processValidationErrors("errMsg", errMsg, returnMav);
		}

		album.setOwnerId(userId);
		album.setId(albumId);
		albumService.editAlbum(album);

		String url = buildRecirectPath(URL_PREFIX + "/list/" + userId);
		url = url + "?curpage=" + page.getCurpage();
		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	/**
	 * 打开创建相册页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/newalbum", method = RequestMethod.GET)
	public ModelAndView newAlbum() {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();
		String userNickname = user.getNickname();
		String userPortrait = user.getPortrait();

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_NEWALBUM);
		view.addObject("ownerId", userId);
		view.addObject("ownerNickname", userNickname);
		view.addObject("ownerPortrait", userPortrait);

		return view;
	}

	/**
	 * 创建用户相册
	 * 
	 * @param album
	 * @return
	 */
	@RequestMapping(value = "/newalbum", method = RequestMethod.POST)
	public ModelAndView newAlbum(Album album) {
		User user = checkAndReturnLoginedUser();

		String errMsg = validateForm("newAlbumForm", album);
		if (errMsg != null) {
			ModelAndView returnMav = newAlbum();
			return processValidationErrors("errMsg", errMsg, returnMav);
		}

		Album resultAlbum = albumService.createAlbum(user, album);
		if (resultAlbum == null) {
			LOGGER.warn("数据异常，如果结果为空，应该早已抛出异常！");
			throw new OperateFailedException("创建相册失败");
		}
		String url = buildRecirectPath(URL_PREFIX + "/bupload/" + resultAlbum.getId());
		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	/**
	 * 打开上传图片到相册的页面
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/upload/{albumId}", method = RequestMethod.GET)
	public ModelAndView toUpload(@PathVariable("albumId") Long albumId) {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();

		Album album = albumService.getAlbumForChange(albumId, userId);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_TOUPLOAD);
		view.addObject("album", album);
		return view;
	}

	/**
	 * 打开批量上传图片到相册的页面
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/bupload/{albumId}", method = RequestMethod.GET)
	public ModelAndView btachUpload(@PathVariable("albumId") Long albumId) {
		User user = checkAndReturnLoginedUser();

		long userId = user.getId();
		Album album = albumService.getAlbumForChange(albumId, userId);
		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_SWFUPLOAD);
		view.addObject("album", album);
		return view;
	}

	/**
	 * 上传图片到相册
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/upload/{albumId}", method = RequestMethod.POST)
	public ModelAndView normalUpload(@PathVariable("albumId") Long albumId, String submitToken,
			MultipartHttpServletRequest request) {
		User user = checkAndReturnLoginedUser();

		String errMsg = validateForm("normalUploadForm", submitToken);
		if (errMsg != null) {
			ModelAndView returnMav = toUpload(albumId);
			return processValidationErrors("errMsg", errMsg, returnMav);
		}

		ModelAndView view = normalUpload(albumId, user, request, ViewPaths.ALBUM_TOUPLOAD, ViewPaths.ALBUM_UPLOADOK);
		return view;
	}

	/**
	 * 批量上传压缩文件
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/buploadok/{albumId}", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> batchUploadOk(@PathVariable("albumId") Long albumId, @RequestParam("files") String files) {
		try {
			User user = checkAndReturnLoginedUser();
			return batchUploadOk(albumId, files, user);
		} catch (NotLoginException e) {
			return toJsonMap(false, "压缩图片必须登录", false);
		} catch (NoResourceException e) {
			LOGGER.warn("压缩图片失败，资源不存在", e);
			return toJsonMap(false, "没有找到对应相册，压缩图片失败！", true);
		} catch (NoOperatePermissionException e) {
			LOGGER.warn("压缩图片失败，无操作权限", e);
			return toJsonMap(false, "没有找到对应相册，压缩图片失败！", true);
		} catch (Exception e) {
			LOGGER.warn("压缩图片失败", e);
			return toJsonMap(false, "压缩图片失败！", true);
		}
	}

	/**
	 * 修改图片信息
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/uploadok/{albumId}", method = RequestMethod.GET)
	public ModelAndView uploadOk(@PathVariable("albumId") Long albumId) {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();
		Album album = albumService.getAlbumForChange(albumId, userId);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_UPLOADOK);
		view.addObject("album", album);

		return view;
	}

	/**
	 * 修改图片信息
	 * 
	 * @param albumId
	 *            相册ID
	 * @param request
	 * */
	@RequestMapping(value = "/uploadok/{albumId}", method = RequestMethod.POST)
	public ModelAndView uploadOk(@PathVariable("albumId") Long albumId, String cover, String ext,
			@RequestParam("description") List<String> descriptions, @RequestParam("id") List<Long> ids,
			String submitToken) {
		User user = checkAndReturnLoginedUser();

		ModelAndView returnMav = null;
		String errMsg = validateForm("uploadOkForm", submitToken);
		if (errMsg != null) {
			returnMav = uploadOk(albumId);
			return processValidationErrors("errMsg", errMsg, returnMav);
		}

		int size = Math.min(ids.size(), descriptions.size());
		StringBuilder errMsgBuilder = new StringBuilder();
		for (int i = 0; i < size; i++) {
			if (ids.get(i) == null) {
				LOGGER.warn("上传后修改图片信息操作失败，ID为:" + albumId + "的相册提交的第" + i + "张图片的ID为空");
				continue;
			}
			errMsg = validateForm("descriptionOnlyForm", descriptions.get(i));
			if (errMsg != null) {
				if (returnMav == null) {
					returnMav = uploadOk(albumId);
				}
				errMsgBuilder.append("第").append(i + 1).append("张图片的").append(errMsg);
				return processValidationErrors("errMsg", errMsgBuilder.toString(), returnMav);
			}
		}

		albumService.changePhotosDescription(albumId, ids, descriptions);
		albumService.changeAlbumCover(user.getId(), albumId, cover, ext);

		WebHelper.removeSessionAttribute(null, Constant.SESSION_UPLOAD_OK_FILES);
		String url = buildRecirectPath(URL_PREFIX + "/view/" + albumId);

		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	@RequestMapping(value = "/delphoto/{photoId}", method = { RequestMethod.POST, RequestMethod.GET })
	public ModelAndView deletePhoto(@PathVariable("photoId") long photoId) {
		long userId = getViewerId();

		Long albumId = albumService.deletePhoto(userId, photoId);

		String url = buildRecirectPath(URL_PREFIX + "/view/" + albumId);
		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	@RequestMapping(value = "/editphoto/{photoId}", method = RequestMethod.GET)
	public ModelAndView editPhoto(@PathVariable("photoId") long photoId) {
		User user = checkAndReturnLoginedUser();
		long userId = user.getId();

		List<Album> albums = albumService.listAlbumNames(userId);
		Photo photo = albumService.getPhotoForChange(userId, photoId);

		ModelAndView view = new ModelAndView(ViewPaths.ALBUM_EDITPHOTO);
		view.addObject("photo", photo);
		view.addObject("albums", albums);

		Long curAlbumId = photo.getAlbumId();
		for (Album album : albums) {
			if (album.getId().equals(curAlbumId)) {
				view.addObject("cover", album.getCover());
			}
		}

		return view;
	}

	@RequestMapping(value = "/editphoto/{photoId}", method = RequestMethod.POST)
	public ModelAndView editPhoto(@PathVariable("photoId") long photoId, String setCover, String toAlbumId,
			@RequestParam("description") String description, String submitToken) {
		User user = checkAndReturnLoginedUser();

		Long toAlbum = NumberUtils.toLong(toAlbumId);

		Map<String, String> formData = new HashMap<String, String>();
		formData.put("submitToken", submitToken);
		formData.put("description", description);
		String errMsg = validateForm("editPhotoForm", formData);
		if (errMsg != null) {
			ModelAndView returnMav = editPhoto(photoId);
			return processValidationErrors("errMsg", errMsg, returnMav);
		}

		long userId = user.getId();
		Photo photo = albumService.getPhotoForChange(userId, photoId);
		Album origAlbum = albumService.getAlbumForChange(photo.getAlbumId(), userId);
		if (setCover == null) {
			if (!photo.getAlbumId().equals(toAlbum)) {
				albumService.changePhotoAlbum(userId, photoId, photo.getAlbumId(), toAlbum);
				if (origAlbum.getCover().equals(photo.getSmallFile())) {// 取消原有封面
					albumService.changeAlbumCover(userId, photo.getAlbumId(), cover, ext);
				}
			}
		} else {
			albumService.changeAlbumCover(userId, photo.getAlbumId(), photo.getSmallFile(), photo.getExt());
		}
		String oldDesc = CommonUtils.nullStringToEmpty(photo.getDescription());
		if (!oldDesc.equals(description)) {
			albumService.changePhotoDescription(photo.getAlbumId(), photoId, description);
		}

		String url = buildRecirectPath(URL_PREFIX + "/photo/" + photoId);
		ModelAndView view = new ModelAndView(new RedirectView(url));
		return view;
	}

	@RequestMapping(value = "/changephotodesc/{photoId}", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> changePhotoDescription(@PathVariable("photoId") long photoId,
			@RequestParam("description") String description) {
		try {
			User user = checkAndReturnLoginedUser();

			Errors errors = ValidationUtils.validateForm("descriptionOnlyForm", description);
			String[] errorMsgs = ValidationUtils.getAllErrorMessages(errors);
			if (errorMsgs.length > 0) {
				return toJsonMap(false, errorMsgs[0], true);
			}

			Photo photo = albumService.getPhotoForChange(user.getId(), photoId);
			String oldDesc = CommonUtils.nullStringToEmpty(photo.getDescription());
			if (!oldDesc.equals(description)) {
				albumService.changePhotoDescription(photo.getAlbumId(), photoId, description);
			}
			return toJsonMap(true, "修改照片描述成功", true);
		} catch (NotLoginException e) {
			LOGGER.error("修改照片描述失败，没有登录", e);
			return toJsonMap(false, "修改照片描述必须登录", false);
		} catch (Exception e) {
			LOGGER.error("修改照片描述失败", e);
			return toJsonMap(false, "修改照片描述失败", true);
		}

	}

	@RequestMapping(value = "/setcover/{photoId}", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> changePhotoCover(@PathVariable("photoId") long photoId) {
		try {
			User user = checkAndReturnLoginedUser();
			Photo photo = albumService.getPhotoForChange(user.getId(), photoId);
			albumService.changeAlbumCover(user.getId(), photo.getAlbumId(), photo.getSmallFile(), photo.getExt());
			return toJsonMap(true, "设置相册封面成功", true);
		} catch (NotLoginException e) {
			LOGGER.error("设置相册封面失败，未登录", e);
			return toJsonMap(false, "设置相册封面必须登录", false);
		} catch (Exception e) {
			LOGGER.error("设置相册封面失败", e);
			return toJsonMap(false, "设置相册封面失败", true);
		}

	}

	@RequestMapping(value = "/viewphoto/{photoId}", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> viewPhoto(@PathVariable("photoId") long photoId) {
		try {
			long viewerId = getViewerId();
			boolean addVisitCount = !checkVisitedAndLogFootprint(photoId, ResourceType.PHOTO);

			Photo photo = albumService.getPhotoDetailById(photoId, viewerId, addVisitCount);
			// 判断权限
			checkAndReturnAuthority(photo);

			Map<String, Object> result = toJsonMap(true, "获取图片成功", true);
			result.put("photo", photo);
			return result;
		} catch (NoVisitPermissionException e) {
			LOGGER.error("没有访问权限", e);
			return toJsonMap(false, "您没有查看该图片的权限", true);
		} catch (NoResourceException e) {
			LOGGER.error("没有资源", e);
			return toJsonMap(false, "没有找到您想查看的图片", true);
		} catch (Exception e) {
			LOGGER.error("", e);
			return toJsonMap(false, "系统发生异常，请稍候再试...", true);
		}
	}

	@RequestMapping(value = "/setportrait/{photoId}", method = RequestMethod.POST)
	@ResponseBody
	public Map<String, Object> changeAsUserPortrait(@PathVariable("photoId") long photoId) {
		try {
			User user = checkAndReturnLoginedUser();
			Long ownerId = user.getId();
			Photo photo = albumService.getPhotoForChange(ownerId, photoId);
			Album portraitAlbum = albumService.getUserPortraitAlbum(ownerId);
			Long albumId = portraitAlbum.getId();
			String photoExt = photo.getExt();
			String remoteFileKey = photo.getSmallFile() + '.' + photoExt;
			if (SkylineImagineUtils.isExtMultiFrame(photoExt)) {// 如果是动态图，需要压缩成单帧图
				remoteFileKey = photo.getMiddleFile() + '.' + photoExt;
				String filename = FilenameUtils.getName(remoteFileKey);
				String fileKey = SkylineImagineUtils.generateFileKey(ownerId.toString(), albumId.toString(), filename);
				String localFile = SkylineImagineUtils.generateFilePath(localStorePath, ownerId, albumId, fileKey + '.'
						+ photoExt);
				File destFile = new File(localFile);

				File dir = destFile.getParentFile();
				if (!dir.exists()) {
					boolean success = dir.mkdirs();
					if (!success && !dir.exists()) {
						LOGGER.warn("mkdirs :" + dir + " failed");
					}
				}
				// 保存服务器上的图片到本地目标文件
				if (fileOperator == null) {
					String srcFile = localStorePath + '/' + remoteFileKey;
					FileUtils.copyFile(new File(srcFile), destFile);
				} else {
					fileOperator.downloadFile(remoteFileKey, localFile);
				}
				// 压缩该目标图片
				LocalImageResizeTask task = new LocalImageResizeTask(localFile, baseSizes);
				task.setAlbumId(albumId);
				task.setUserId(ownerId);
				task.setSupportMulitFrame(false);
				ImageResizeResult resizeResult = imagine.processSingleImage(localStorePath, task);
				Photo portrait = albumService.createPortraitPhoto(user, portraitAlbum, resizeResult);
				remoteFileKey = portrait.getSmallFile() + '.' + portrait.getExt();
			} else {
				albumService.copyPhotoToPortraitAlbum(portraitAlbum, photo);
			}

			SkylineImageCropTask cropTask = new SkylineImageCropTask(remoteFileKey, portraitSize);
			cropTask.setAlbumId(albumId);
			cropTask.setUserId(ownerId);
			ImageCropResult cropResult = crop.processImage(localStorePath, cropTask);
			String portraitFile = cropResult.getFileKey();

			personalInfoService.changeUserPortrait(ownerId, portraitFile);
			user.setPortrait(portraitFile);
			WebHelper.setSessionAttribute(null, Constant.SESSION_USER, user);

			return toJsonMap(true, "设置头像成功", true);
		} catch (NotLoginException e) {
			LOGGER.error("设置相册封面失败，需要登录", e);
			return toJsonMap(false, "设置头像必须登录", false);
		} catch (Exception e) {
			LOGGER.error("设置相册封面失败", e);
			return toJsonMap(false, "设置头像失败", true);
		}

	}

}
